#include "Viewer.h"
#include "Cube.h"
#include "Box.h"
#include "Sphere.h"
#include "Plane.h"
#include "MeshObject.h"
#include "elementconfig.h"
#include "stdio.h"

using namespace std;
using namespace qglviewer;

/*!
  Responsable for showing the worlds elements (sphere, box, robot ...).
  Inherited QWidget.
  */
Viewer::Viewer(QWidget *parent)
    : QGLViewer(QGLFormat(QGL::SampleBuffers |
		QGL::DoubleBuffer |
		QGL::DepthBuffer |
		QGL::Rgba |
		QGL::AlphaChannel |
		QGL::StencilBuffer),parent)
{
}

Viewer::~Viewer()
{
}
/*!
  Sets the scenes size & some lights
  */
void Viewer::init()
{
    //printf("init\n");
    Vec center(0.0, 0.0, 0.0);
    setSceneRadius(100.0);
    setSceneCenter(center);
    showEntireScene();

    // Setup OpenGL
    GLfloat ambient[] = { 0.3f, 0.3f, 0.3f };
    GLfloat diffuse[] = { 0.1f, 0.1f, 0.1f , 1.0f};
    GLfloat specular[] = { 0.0f, 0.0f, 0.0f , 1.0f};
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);

    startAnimation();
}

/*!
  The drawind function. Draws every single added object.
  */
void Viewer::draw()
{
    foreach (Element *o,_elements)
    {
	o->render();
    }

    foreach (Element *o, _staticElements)
    {
        o->render();
    }
}

/*!
  Starts the animation
  */
void Viewer::startAnimation()
{
    QGLViewer::startAnimation();
}

/*!
  The animate function. Same as the default.
  */
void Viewer::animate()
{
    // nothing spec
}

/*!
  Adds an element to the vector of the shown elements.
  @type: the type of the object
  @m: the initial transformation matrix of the element
  @c: the color of the element (R, G, B)
  @d: aditional data for the element (ex: size)
  */
void Viewer::addElement(ElementType type, float *m, unsigned char *c, void *d)
{
    switch (type)
    {
    case CubeType:
        {
            float *v = (float *)d;
            printf("New Cube: %f\n", v[0]);
            Element *cube = new Cube(v[0], c, m);
            _elements.push_back(cube);
            break;
        }
    case SphereType:
        {
            float *v = (float *)d;
            printf("New Sphere: %f\n", v[0]);

            Element *sphere = new Sphere(v[0], c, m);
            _elements.push_back(sphere);
            break;
        }
    case MeshType:
        {
//            char *name = (char* ) v;
            /*printf("New Mesh\n");*/

            char *name = new char[10];
            strcpy(name, "xr1_weel");
            Element *mesh = new MeshObject(name, c, m);
            _elements.push_back(mesh);

//            float x = 1.0;
//            printf("New Cube: %f\n", x);
//            Element *cube = new Cube(x, c, m);
//            _elements.push_back(cube);
            break;
        }
    case BoxType:
        {
            float *v = (float *)d;
            printf("New Box: %f %f %f\n", v[0], v[1], v[2]);
            Element *box = new Box(v[0], v[1], v[2], c, m);
            _elements.push_back(box);
            break;
        }
    default:
        printf("fail?\n");
        break;
    }
}

/*!
  Updates the non-static objects transformation matrix
  */
void Viewer::UpdateObjects(float *m)
{
    int i = 0;
    foreach (Element *o, _elements)
    {
        o->setTransMatrix(&m[i * 4 * 4]);
        ++i;
    }
}

void Viewer::addElement(Element *e)
{
    _elements.push_back(e);
}

/*!
  Adds a static element to the vector of the shown elements.
  */
void Viewer::addStaticElement(Element *e)
{
    _staticElements.push_back(e);
}

/*!
  Deletes all of the elements
  */
void Viewer::clearElements()
{
    _elements.clear();
}
